/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @format
 * @flow strict-local
 */
//'use strict';
//import MiotAndroidScrollView from 'react-native/Libraries/Components/ScrollView/ScrollView'
//
//export default MiotAndroidScrollView
'use strict';
import {
    ScrollView,
    Platform,
    Animated,
    ColorPropType,
    EdgeInsetsPropType,
    PointPropType,
    StyleSheet,
    ViewPropTypes,
} from 'react-native';
//const Animated = require('Animated');
//const ColorPropType = require('ColorPropType');
//const EdgeInsetsPropType = require('EdgeInsetsPropType');
//const PointPropType = require('PointPropType');
const PropTypes = require('prop-types');
const React = require('react');//const React = require('React');
const ReactNative = require('react-native');//const ReactNative = require('ReactNative');
import ScrollResponder from 'react-native/Libraries/Components/ScrollResponder';//const ScrollResponder = require('ScrollResponder');
import ScrollViewStickyHeader from 'react-native/Libraries/Components/ScrollView/ScrollViewStickyHeader';//const ScrollViewStickyHeader = require('ScrollViewStickyHeader');
//const StyleSheet = require('StyleSheet');
import StyleSheetPropType from 'react-native/Libraries/DeprecatedPropTypes/DeprecatedStyleSheetPropType';//const StyleSheetPropType = require('StyleSheetPropType');
import View from 'react-native/Libraries/Components/View/View';//const View = require('View');
//const ViewPropTypes = require('ViewPropTypes');
import ViewStylePropTypes from 'react-native/Libraries/DeprecatedPropTypes/DeprecatedViewStylePropTypes';//const ViewStylePropTypes = require('ViewStylePropTypes');
const createReactClass = require('create-react-class');
import dismissKeyboard from 'react-native/Libraries/Utilities/dismissKeyboard';//const dismissKeyboard = require('dismissKeyboard');
import flattenStyle from 'react-native/Libraries/StyleSheet/flattenStyle';//const flattenStyle = require('flattenStyle');
const invariant = require('fbjs/lib/invariant');
import processDecelerationRate from './DecelerationRate';
import requireNativeComponent from 'react-native/Libraries/ReactNative/requireNativeComponent';//const requireNativeComponent = require('requireNativeComponent');
/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error
 * found when Flow v0.54 was deployed. To see the error delete this comment and
 * run Flow. */
const warning = require('fbjs/lib/warning');
import resolveAssetSource from 'react-native/Libraries/Image/resolveAssetSource';//const resolveAssetSource = require('resolveAssetSource');
import type {NativeMethodsMixinType} from 'ReactNativeTypes';
/**
 * Component that wraps platform ScrollView while providing
 * integration with touch locking "responder" system.
 *
 * Keep in mind that ScrollViews must have a bounded height in order to work,
 * since they contain unbounded-height children into a bounded container (via
 * a scroll interaction). In order to bound the height of a ScrollView, either
 * set the height of the view directly (discouraged) or make sure all parent
 * views have bounded height. Forgetting to transfer `{flex: 1}` down the
 * view stack can lead to errors here, which the element inspector makes
 * easy to debug.
 *
 * Doesn't yet support other contained responders from blocking this scroll
 * view from becoming the responder.
 *
 *
 * `<ScrollView>` vs [`<FlatList>`](/react-native/docs/flatlist.html) - which one to use?
 *
 * `ScrollView` simply renders all its react child components at once. That
 * makes it very easy to understand and use.
 *
 * On the other hand, this has a performance downside. Imagine you have a very
 * long list of items you want to display, maybe several screens worth of
 * content. Creating JS components and native views for everything all at once,
 * much of which may not even be shown, will contribute to slow rendering and
 * increased memory usage.
 *
 * This is where `FlatList` comes into play. `FlatList` renders items lazily,
 * just when they are about to appear, and removes items that scroll way off
 * screen to save memory and processing time.
 *
 * `FlatList` is also handy if you want to render separators between your items,
 * multiple columns, infinite scroll loading, or any number of other features it
 * supports out of the box.
 */
// $FlowFixMe(>=0.41.0)
const MiotAndroidScrollView = createReactClass({
    displayName: 'MiotAndroidScrollView',
    propTypes: {
        ...ViewPropTypes,
        /**
         * Controls whether iOS should automatically adjust the content inset
         * for scroll views that are placed behind a navigation bar or
         * tab bar/ toolbar. The default value is true.
         * @platform ios
         */
        automaticallyAdjustContentInsets: PropTypes.bool,
        /**
         * The amount by which the scroll view content is inset from the edges
         * of the scroll view. Defaults to `{top: 0, left: 0, bottom: 0, right: 0}`.
         * @platform ios
         */
        contentInset: EdgeInsetsPropType,
        /**
         * Used to manually set the starting scroll offset.
         * The default value is `{x: 0, y: 0}`.
         * @platform ios
         */
        contentOffset: PointPropType,
        /**
         * When true, the scroll view bounces when it reaches the end of the
         * content if the content is larger then the scroll view along the axis of
         * the scroll direction. When false, it disables all bouncing even if
         * the `alwaysBounce*` props are true. The default value is true.
         * @platform ios
         */
        bounces: PropTypes.bool,
        /**
         * When true, gestures can drive zoom past min/max and the zoom will animate
         * to the min/max value at gesture end, otherwise the zoom will not exceed
         * the limits.
         * @platform ios
         */
        bouncesZoom: PropTypes.bool,
        /**
         * When true, the scroll view bounces horizontally when it reaches the end
         * even if the content is smaller than the scroll view itself. The default
         * value is true when `horizontal={true}` and false otherwise.
         * @platform ios
         */
        alwaysBounceHorizontal: PropTypes.bool,
        /**
         * When true, the scroll view bounces vertically when it reaches the end
         * even if the content is smaller than the scroll view itself. The default
         * value is false when `horizontal={true}` and true otherwise.
         * @platform ios
         */
        alwaysBounceVertical: PropTypes.bool,
        /**
         * When true, the scroll view automatically centers the content when the
         * content is smaller than the scroll view bounds; when the content is
         * larger than the scroll view, this property has no effect. The default
         * value is false.
         * @platform ios
         */
        centerContent: PropTypes.bool,
        /**
         * These styles will be applied to the scroll view content container which
         * wraps all of the child views. Example:
         *
         * ```
         * return (
         *   <ScrollView contentContainerStyle={styles.contentContainer}>
         *   </ScrollView>
         * );
         * ...
         * const styles = StyleSheet.create({
         *   contentContainer: {
         *     paddingVertical: 20
         *   }
         * });
         * ```
         */
        contentContainerStyle: StyleSheetPropType(ViewStylePropTypes),
        /**
         * A floating-point number that determines how quickly the scroll view
         * decelerates after the user lifts their finger. You may also use string
         * shortcuts `"normal"` and `"fast"` which match the underlying iOS settings
         * for `UIScrollViewDecelerationRateNormal` and
         * `UIScrollViewDecelerationRateFast` respectively.
         *
         *   - `'normal'`: 0.998 (the default)
         *   - `'fast'`: 0.99
         *
         * @platform ios
         */
        decelerationRate: PropTypes.oneOfType([
            PropTypes.oneOf(['fast', 'normal']),
            PropTypes.number,
        ]),
        /**
         * When true, the scroll view's children are arranged horizontally in a row
         * instead of vertically in a column. The default value is false.
         */
        horizontal: PropTypes.bool,
        /**
         * The style of the scroll indicators.
         *
         *   - `'default'` (the default), same as `black`.
         *   - `'black'`, scroll indicator is black. This style is good against a light background.
         *   - `'white'`, scroll indicator is white. This style is good against a dark background.
         *
         * @platform ios
         */
        indicatorStyle: PropTypes.oneOf([
            'default', // default
            'black',
            'white',
        ]),
        /**
         * If sticky headers should stick at the bottom instead of the top of the
         * ScrollView. This is usually used with inverted ScrollViews.
         */
        invertStickyHeaders: PropTypes.bool,
        /**
         * When true, the ScrollView will try to lock to only vertical or horizontal
         * scrolling while dragging.  The default value is false.
         * @platform ios
         */
        directionalLockEnabled: PropTypes.bool,
        /**
         * When false, once tracking starts, won't try to drag if the touch moves.
         * The default value is true.
         * @platform ios
         */
        canCancelContentTouches: PropTypes.bool,
        /**
         * Determines whether the keyboard gets dismissed in response to a drag.
         *
         * *Cross platform*
         *
         *   - `'none'` (the default), drags do not dismiss the keyboard.
         *   - `'on-drag'`, the keyboard is dismissed when a drag begins.
         *
         * *iOS Only*
         *
         *   - `'interactive'`, the keyboard is dismissed interactively with the drag and moves in
         *     synchrony with the touch; dragging upwards cancels the dismissal.
         *     On android this is not supported and it will have the same behavior as 'none'.
         */
        keyboardDismissMode: PropTypes.oneOf([
            'none', // default
            'on-drag', // Cross-platform
            'interactive', // iOS-only
        ]),
        /**
         * Determines when the keyboard should stay visible after a tap.
         *
         *   - `'never'` (the default), tapping outside of the focused text input when the keyboard
         *     is up dismisses the keyboard. When this happens, children won't receive the tap.
         *   - `'always'`, the keyboard will not dismiss automatically, and the scroll view will not
         *     catch taps, but children of the scroll view can catch taps.
         *   - `'handled'`, the keyboard will not dismiss automatically when the tap was handled by
         *     a children, (or captured by an ancestor).
         *   - `false`, deprecated, use 'never' instead
         *   - `true`, deprecated, use 'always' instead
         */
        keyboardShouldPersistTaps: PropTypes.oneOf(['always', 'never', 'handled', false, true]),
        /**
         * When set, the scroll view will adjust the scroll position so that the first child that is
         * currently visible and at or beyond `minIndexForVisible` will not change position. This is
         * useful for lists that are loading content in both directions, e.g. a chat thread, where new
         * messages coming in might otherwise cause the scroll position to jump. A value of 0 is common,
         * but other values such as 1 can be used to skip loading spinners or other content that should
         * not maintain position.
         *
         * The optional `autoscrollToTopThreshold` can be used to make the content automatically scroll
         * to the top after making the adjustment if the user was within the threshold of the top before
         * the adjustment was made. This is also useful for chat-like applications where you want to see
         * new messages scroll into place, but not if the user has scrolled up a ways and it would be
         * disruptive to scroll a bunch.
         *
         * Caveat 1: Reordering elements in the scrollview with this enabled will probably cause
         * jumpiness and jank. It can be fixed, but there are currently no plans to do so. For now,
         * don't re-order the content of any ScrollViews or Lists that use this feature.
         *
         * Caveat 2: This simply uses `contentOffset` and `frame.origin` in native code to compute
         * visibility. Occlusion, transforms, and other complexity won't be taken into account as to
         * whether content is "visible" or not.
         *
         * @platform ios
         */
        maintainVisibleContentPosition: PropTypes.shape({
            minIndexForVisible: PropTypes.number.isRequired,
            autoscrollToTopThreshold: PropTypes.number,
        }),
        /**
         * The maximum allowed zoom scale. The default value is 1.0.
         * @platform ios
         */
        maximumZoomScale: PropTypes.number,
        /**
         * The minimum allowed zoom scale. The default value is 1.0.
         * @platform ios
         */
        minimumZoomScale: PropTypes.number,
        /**
         * Called when the momentum scroll starts (scroll which occurs as the ScrollView glides to a stop).
         */
        onMomentumScrollBegin: PropTypes.func,
        /**
         * Called when the momentum scroll ends (scroll which occurs as the ScrollView glides to a stop).
         */
        onMomentumScrollEnd: PropTypes.func,
        /**
         * Fires at most once per frame during scrolling. The frequency of the
         * events can be controlled using the `scrollEventThrottle` prop.
         */
        onScroll: PropTypes.func,
        /**
         * Called when the user begins to drag the scroll view.
         */
        onScrollBeginDrag: PropTypes.func,
        /**
         * Called when the user stops dragging the scroll view and it either stops
         * or begins to glide.
         */
        onScrollEndDrag: PropTypes.func,
        /**
         * Called when scrollable content view of the ScrollView changes.
         *
         * Handler function is passed the content width and content height as parameters:
         * `(contentWidth, contentHeight)`
         *
         * It's implemented using onLayout handler attached to the content container
         * which this ScrollView renders.
         */
        onContentSizeChange: PropTypes.func,
        /**
         * When true, the scroll view stops on multiples of the scroll view's size
         * when scrolling. This can be used for horizontal pagination. The default
         * value is false.
         *
         * Note: Vertical pagination is not supported on Android.
         */
        pagingEnabled: PropTypes.bool,
        /**
         * When true, ScrollView allows use of pinch gestures to zoom in and out.
         * The default value is true.
         * @platform ios
         */
        pinchGestureEnabled: PropTypes.bool,
        /**
         * When false, the view cannot be scrolled via touch interaction.
         * The default value is true.
         *
         * Note that the view can always be scrolled by calling `scrollTo`.
         */
        scrollEnabled: PropTypes.bool,
        /**
         * This controls how often the scroll event will be fired while scrolling
         * (as a time interval in ms). A lower number yields better accuracy for code
         * that is tracking the scroll position, but can lead to scroll performance
         * problems due to the volume of information being send over the bridge.
         * You will not notice a difference between values set between 1-16 as the
         * JS run loop is synced to the screen refresh rate. If you do not need precise
         * scroll position tracking, set this value higher to limit the information
         * being sent across the bridge. The default value is zero, which results in
         * the scroll event being sent only once each time the view is scrolled.
         * @platform ios
         */
        scrollEventThrottle: PropTypes.number,
        /**
         * The amount by which the scroll view indicators are inset from the edges
         * of the scroll view. This should normally be set to the same value as
         * the `contentInset`. Defaults to `{0, 0, 0, 0}`.
         * @platform ios
         */
        scrollIndicatorInsets: EdgeInsetsPropType,
        /**
         * When true, the scroll view scrolls to top when the status bar is tapped.
         * The default value is true.
         * @platform ios
         */
        scrollsToTop: PropTypes.bool,
        /**
         * When true, shows a horizontal scroll indicator.
         * The default value is true.
         */
        showsHorizontalScrollIndicator: PropTypes.bool,
        /**
         * When true, shows a vertical scroll indicator.
         * The default value is true.
         */
        showsVerticalScrollIndicator: PropTypes.bool,
        /**
         * An array of child indices determining which children get docked to the
         * top of the screen when scrolling. For example, passing
         * `stickyHeaderIndices={[0]}` will cause the first child to be fixed to the
         * top of the scroll view. This property is not supported in conjunction
         * with `horizontal={true}`.
         */
        stickyHeaderIndices: PropTypes.arrayOf(PropTypes.number),
        /**
         * When set, causes the scroll view to stop at multiples of the value of
         * `snapToInterval`. This can be used for paginating through children
         * that have lengths smaller than the scroll view. Typically used in
         * combination with `snapToAlignment` and `decelerationRate="fast"` on ios.
         * Overrides less configurable `pagingEnabled` prop.
         *
         * Supported for horizontal scrollview on android.
         */
        snapToInterval: PropTypes.number,
        /**
         * When `snapToInterval` is set, `snapToAlignment` will define the relationship
         * of the snapping to the scroll view.
         *
         *   - `'start'` (the default) will align the snap at the left (horizontal) or top (vertical)
         *   - `'center'` will align the snap in the center
         *   - `'end'` will align the snap at the right (horizontal) or bottom (vertical)
         *
         * @platform ios
         */
        snapToAlignment: PropTypes.oneOf([
            'start', // default
            'center',
            'end',
        ]),
        /**
         * Experimental: When true, offscreen child views (whose `overflow` value is
         * `hidden`) are removed from their native backing superview when offscreen.
         * This can improve scrolling performance on long lists. The default value is
         * true.
         */
        removeClippedSubviews: PropTypes.bool,
        /**
         * The current scale of the scroll view content. The default value is 1.0.
         * @platform ios
         */
        zoomScale: PropTypes.number,
        /**
         * This property specifies how the safe area insets are used to modify the
         * content area of the scroll view. The default value of this property is
         * "never". Available on iOS 11 and later.
         * @platform ios
         */
        contentInsetAdjustmentBehavior: PropTypes.oneOf([
            'automatic',
            'scrollableAxes',
            'never', // default
            'always',
        ]),
        /**
         * A RefreshControl component, used to provide pull-to-refresh
         * functionality for the ScrollView. Only works for vertical ScrollViews
         * (`horizontal` prop must be `false`).
         *
         * See [RefreshControl](docs/refreshcontrol.html).
         */
        refreshControl: PropTypes.element,
        /**
         * Sometimes a scrollview takes up more space than its content fills. When this is
         * the case, this prop will fill the rest of the scrollview with a color to avoid setting
         * a background and creating unnecessary overdraw. This is an advanced optimization
         * that is not needed in the general case.
         * @platform android
         */
        endFillColor: ColorPropType,
        /**
         * Tag used to log scroll performance on this scroll view. Will force
         * momentum events to be turned on (see sendMomentumEvents). This doesn't do
         * anything out of the box and you need to implement a custom native
         * FpsListener for it to be useful.
         * @platform android
         */
        scrollPerfTag: PropTypes.string,
        /**
         * Used to override default value of overScroll mode.
         *
         * Possible values:
         *
         *  - `'auto'` - Default value, allow a user to over-scroll
         *    this view only if the content is large enough to meaningfully scroll.
         *  - `'always'` - Always allow a user to over-scroll this view.
         *  - `'never'` - Never allow a user to over-scroll this view.
         *
         * @platform android
         */
        overScrollMode: PropTypes.oneOf([
            'auto',
            'always',
            'never',
        ]),
        /**
         * When true, ScrollView will emit updateChildFrames data in scroll events,
         * otherwise will not compute or emit child frame data.  This only exists
         * to support legacy issues, `onLayout` should be used instead to retrieve
         * frame data.
         * The default value is false.
         * @platform ios
         */
        DEPRECATED_sendUpdatedChildFrames: PropTypes.bool,
        /**
         * Optionally an image can be used for the scroll bar thumb. This will
         * override the color. While the image is loading or the image fails to
         * load the color will be used instead. Use an alpha of 0 in the color
         * to avoid seeing it while the image is loading.
         *
         * - `uri` - a string representing the resource identifier for the image, which
         * should be either a local file path or the name of a static image resource
         * - `number` - Opaque type returned by something like
         * `import IMAGE from './image.jpg'`.
         * @platform vr
         */
        scrollBarThumbImage: PropTypes.oneOfType([
            PropTypes.shape({
                uri: PropTypes.string,
            }),
            // Opaque type returned by import IMAGE from './image.jpg'
            PropTypes.number,
        ]),
        /**
         * 吸附临界点
         * @platform android
         */
        snapHeight: PropTypes.number,
        /**
         *  吸附动画时间
         *  @platform android
         */
        scrollYDuration: PropTypes.number
    },
    mixins: [ScrollResponder.Mixin],
    _scrollAnimatedValue: (new Animated.Value(0): Animated.Value),
    _scrollAnimatedValueAttachment: (null: ?{detach: () => void}),
    _stickyHeaderRefs: (new Map(): Map<number, ScrollViewStickyHeader>),
    _headerLayoutYs: (new Map(): Map<string, number>),
    getInitialState: function() {
        return {
            ...this.scrollResponderMixinGetInitialState(),
            layoutHeight: null,
        };
    },
    UNSAFE_componentWillMount: function() {
        this._scrollAnimatedValue = new Animated.Value(this.props.contentOffset ? this.props.contentOffset.y : 0);
        this._scrollAnimatedValue.setOffset(this.props.contentInset ? this.props.contentInset.top : 0);
        this._stickyHeaderRefs = new Map();
        this._headerLayoutYs = new Map();
    },
    componentDidMount: function() {
        this._updateAnimatedNodeAttachment();
    },
    componentDidUpdate: function() {
        this._updateAnimatedNodeAttachment();
    },
    componentWillUnmount: function() {
        if (this._scrollAnimatedValueAttachment) {
            this._scrollAnimatedValueAttachment.detach();
        }
    },
    setNativeProps: function(props: Object) {
        this._scrollViewRef && this._scrollViewRef.setNativeProps(props);
    },
    /**
     * Returns a reference to the underlying scroll responder, which supports
     * operations like `scrollTo`. All ScrollView-like components should
     * implement this method so that they can be composed while providing access
     * to the underlying scroll responder's methods.
     */
    getScrollResponder: function(): ScrollView {
        return this;
    },
    getScrollableNode: function(): any {
        return ReactNative.findNodeHandle(this._scrollViewRef);
    },
    getInnerViewNode: function(): any {
        return ReactNative.findNodeHandle(this._innerViewRef);
    },
    /**
     * Scrolls to a given x, y offset, either immediately or with a smooth animation.
     *
     * Example:
     *
     * `scrollTo({x: 0, y: 0, animated: true})`
     *
     * Note: The weird function signature is due to the fact that, for historical reasons,
     * the function also accepts separate arguments as an alternative to the options object.
     * This is deprecated due to ambiguity (y before x), and SHOULD NOT BE USED.
     */
    scrollTo: function(
        y?: number | { x?: number, y?: number, animated?: boolean },
        x?: number,
        animated?: boolean
    ) {
        if (typeof y === 'number') {
            console.warn('`scrollTo(y, x, animated)` is deprecated. Use `scrollTo({x: 5, y: 5, ' +
                'animated: true})` instead.');
        } else {
            ({x, y, animated} = y || {});
        }
        this.getScrollResponder().scrollResponderScrollTo(
            {x: x || 0, y: y || 0, animated: animated !== false}
        );
    },
    /**
     * If this is a vertical ScrollView scrolls to the bottom.
     * If this is a horizontal ScrollView scrolls to the right.
     *
     * Use `scrollToEnd({animated: true})` for smooth animated scrolling,
     * `scrollToEnd({animated: false})` for immediate scrolling.
     * If no options are passed, `animated` defaults to true.
     */
    scrollToEnd: function(
        options?: { animated?: boolean },
    ) {
        // Default to true
        const animated = (options && options.animated) !== false;
        this.getScrollResponder().scrollResponderScrollToEnd({
            animated: animated,
        });
    },
    /**
     * Deprecated, use `scrollTo` instead.
     */
    scrollWithoutAnimationTo: function(y: number = 0, x: number = 0) {
        console.warn('`scrollWithoutAnimationTo` is deprecated. Use `scrollTo` instead');
        this.scrollTo({x, y, animated: false});
    },
    /**
     * Displays the scroll indicators momentarily.
     *
     * @platform ios
     */
    flashScrollIndicators: function() {
        this.getScrollResponder().scrollResponderFlashScrollIndicators();
    },
    _getKeyForIndex: function(index, childArray) {
        const child = childArray[index];
        return child && child.key;
    },
    _updateAnimatedNodeAttachment: function() {
        if (this._scrollAnimatedValueAttachment) {
            this._scrollAnimatedValueAttachment.detach();
        }
        if (this.props.stickyHeaderIndices && this.props.stickyHeaderIndices.length > 0) {
            this._scrollAnimatedValueAttachment = Animated.attachNativeEvent(
                this._scrollViewRef,
                'onScroll',
                [{nativeEvent: {contentOffset: {y: this._scrollAnimatedValue}}}]
            );
        }
    },
    _setStickyHeaderRef: function(key, ref) {
        if (ref) {
            this._stickyHeaderRefs.set(key, ref);
        } else {
            this._stickyHeaderRefs.delete(key);
        }
    },
    _onStickyHeaderLayout: function(index, event, key) {
        if (!this.props.stickyHeaderIndices) {
            return;
        }
        const childArray = React.Children.toArray(this.props.children);
        if (key !== this._getKeyForIndex(index, childArray)) {
            // ignore stale layout update
            return;
        }
        const layoutY = event.nativeEvent.layout.y;
        this._headerLayoutYs.set(key, layoutY);
        const indexOfIndex = this.props.stickyHeaderIndices.indexOf(index);
        const previousHeaderIndex = this.props.stickyHeaderIndices[indexOfIndex - 1];
        if (previousHeaderIndex != null) {
            const previousHeader = this._stickyHeaderRefs.get(
                this._getKeyForIndex(previousHeaderIndex, childArray)
            );
            previousHeader && previousHeader.setNextHeaderY(layoutY);
        }
    },
    _handleScroll: function(e: Object) {
        if (__DEV__) {
            if (this.props.onScroll && this.props.scrollEventThrottle == null && Platform.OS === 'ios') {
                console.log(
                    'You specified `onScroll` on a <ScrollView> but not ' +
                    '`scrollEventThrottle`. You will only receive one event. ' +
                    'Using `16` you get all the events but be aware that it may ' +
                    'cause frame drops, use a bigger number if you don\'t need as ' +
                    'much precision.'
                );
            }
        }
        if (Platform.OS === 'android') {
            if (this.props.keyboardDismissMode === 'on-drag') {
                dismissKeyboard();
            }
        }
        this.scrollResponderHandleScroll(e);
    },
    _handleLayout: function(e: Object) {
        if (this.props.invertStickyHeaders) {
            this.setState({ layoutHeight: e.nativeEvent.layout.height });
        }
        if (this.props.onLayout) {
            this.props.onLayout(e);
        }
    },
    _handleContentOnLayout: function(e: Object) {
        const {width, height} = e.nativeEvent.layout;
        this.props.onContentSizeChange && this.props.onContentSizeChange(width, height);
    },
    _scrollViewRef: (null: ?ScrollView),
    _setScrollViewRef: function(ref: ?ScrollView) {
        this._scrollViewRef = ref;
    },
    _innerViewRef: (null: ?NativeMethodsMixinType),
    _setInnerViewRef: function(ref: ?NativeMethodsMixinType) {
        this._innerViewRef = ref;
    },
    render: function() {
        let useVerticalCustom = false;
        if (Platform.OS === 'android') {
            if (!this.props.horizontal) {
                useVerticalCustom = !!this.props.snapHeight;
            }
        }
        if(useVerticalCustom) {
            const contentContainerStyle = [
                this.props.contentContainerStyle,
            ];
            let style, childLayoutProps;
            if (__DEV__ && this.props.style) {
                style = flattenStyle(this.props.style);
                childLayoutProps = ['alignItems', 'justifyContent']
                    .filter((prop) => style && style[prop] !== undefined);
                invariant(
                    childLayoutProps.length === 0,
                    'ScrollView child layout (' + JSON.stringify(childLayoutProps) +
                    ') must be applied through the contentContainerStyle prop.'
                );
            }
            let contentSizeChangeProps = {};
            if (this.props.onContentSizeChange) {
                contentSizeChangeProps = {
                    onLayout: this._handleContentOnLayout,
                };
            }
            const {stickyHeaderIndices} = this.props;
            const hasStickyHeaders = stickyHeaderIndices && stickyHeaderIndices.length > 0;
            const childArray = hasStickyHeaders && React.Children.toArray(this.props.children);
            const children = hasStickyHeaders ?
                childArray.map((child, index) => {
                    const indexOfIndex = child ? stickyHeaderIndices.indexOf(index) : -1;
                    if (indexOfIndex > -1) {
                        const key = child.key;
                        const nextIndex = stickyHeaderIndices[indexOfIndex + 1];
                        return (
                            <ScrollViewStickyHeader
                                key={key}
                                ref={(ref) => this._setStickyHeaderRef(key, ref)}
                                nextHeaderLayoutY={
                                    this._headerLayoutYs.get(this._getKeyForIndex(nextIndex, childArray))
                                }
                                onLayout={(event) => this._onStickyHeaderLayout(index, event, key)}
                                scrollAnimatedValue={this._scrollAnimatedValue}
                                inverted={this.props.invertStickyHeaders}
                                scrollViewHeight={this.state.layoutHeight}>
                                {child}
                            </ScrollViewStickyHeader>
                        );
                    } else {
                        return child;
                    }
                }) :
                this.props.children;
            const contentContainer =
                <View
                    {...contentSizeChangeProps}
                    ref={this._setInnerViewRef}
                    style={contentContainerStyle}
                    removeClippedSubviews={
                        // Subview clipping causes issues with sticky headers on Android and
                        // would be hard to fix properly in a performant way.
                        Platform.OS === 'android' && hasStickyHeaders ?
                            false :
                            this.props.removeClippedSubviews
                    }
                    collapsable={false}>
                    {children}
                </View>;
            const alwaysBounceVertical =
                this.props.alwaysBounceVertical !== undefined ?
                    this.props.alwaysBounceVertical :
                    !this.props.horizontal;
            const DEPRECATED_sendUpdatedChildFrames =
                !!this.props.DEPRECATED_sendUpdatedChildFrames;
            const baseStyle = styles.baseVertical;
            const props = {
                ...this.props,
                alwaysBounceVertical,
                style: ([baseStyle, this.props.style]: ?Array<any>),
                // Override the onContentSizeChange from props, since this event can
                // bubble up from TextInputs
                onContentSizeChange: null,
                onLayout: this._handleLayout,
                onMomentumScrollBegin: this.scrollResponderHandleMomentumScrollBegin,
                onMomentumScrollEnd: this.scrollResponderHandleMomentumScrollEnd,
                onResponderGrant: this.scrollResponderHandleResponderGrant,
                onResponderReject: this.scrollResponderHandleResponderReject,
                onResponderRelease: this.scrollResponderHandleResponderRelease,
                onResponderTerminate: this.scrollResponderHandleTerminate,
                onResponderTerminationRequest: this.scrollResponderHandleTerminationRequest,
                onScroll: this._handleScroll,
                onScrollBeginDrag: this.scrollResponderHandleScrollBeginDrag,
                onScrollEndDrag: this.scrollResponderHandleScrollEndDrag,
                onScrollShouldSetResponder: this.scrollResponderHandleScrollShouldSetResponder,
                onStartShouldSetResponder: this.scrollResponderHandleStartShouldSetResponder,
                onStartShouldSetResponderCapture: this.scrollResponderHandleStartShouldSetResponderCapture,
                onTouchEnd: this.scrollResponderHandleTouchEnd,
                onTouchMove: this.scrollResponderHandleTouchMove,
                onTouchStart: this.scrollResponderHandleTouchStart,
                onTouchCancel: this.scrollResponderHandleTouchCancel,
                scrollBarThumbImage: resolveAssetSource(this.props.scrollBarThumbImage),
                scrollEventThrottle: hasStickyHeaders ? 1 : this.props.scrollEventThrottle,
                sendMomentumEvents: (this.props.onMomentumScrollBegin || this.props.onMomentumScrollEnd) ?
                    true : false,
                pagingEnabled: true,
                DEPRECATED_sendUpdatedChildFrames,
            };
            const {decelerationRate} = this.props;
            if (decelerationRate) {
                props.decelerationRate = processDecelerationRate(decelerationRate);
            }
            const refreshControl = this.props.refreshControl;
            if (refreshControl) {
                if (Platform.OS === 'android') {
                    // On Android wrap the ScrollView with a AndroidSwipeRefreshLayout.
                    // Since the ScrollView is wrapped add the style props to the
                    // AndroidSwipeRefreshLayout and use flex: 1 for the ScrollView.
                    // Note: we should only apply props.style on the wrapper
                    // however, the ScrollView still needs the baseStyle to be scrollable
                    return React.cloneElement(
                        refreshControl,
                        {style: props.style},
                        <AndroidScrollView {...props} style={baseStyle} ref={this._setScrollViewRef}>
                            {contentContainer}
                        </AndroidScrollView>
                    );
                }
            }
            return (
                <AndroidScrollView {...props} ref={this._setScrollViewRef}>
                    {contentContainer}
                </AndroidScrollView>
            );
        }
    }
});
const styles = StyleSheet.create({
    baseVertical: {
        flexGrow: 1,
        flexShrink: 1,
        flexDirection: 'column',
        overflow: 'scroll',
    },
    baseHorizontal: {
        flexGrow: 1,
        flexShrink: 1,
        flexDirection: 'row',
        overflow: 'scroll',
    },
    contentContainerHorizontal: {
        flexDirection: 'row',
    },
});
let nativeOnlyProps,
    AndroidScrollView;
if (Platform.OS === 'android') {
    nativeOnlyProps = {
        nativeOnly: {
            sendMomentumEvents: true,
        }
    };
    AndroidScrollView = requireNativeComponent(
        'MIOTAndroidScrollView',
        (AndroidScrollView: React.ComponentType<any>),
        nativeOnlyProps
    );
}
export  default MiotAndroidScrollView;